<template>
  <div>
    <el-card v-if="header" style="margin: 20px; border-radius: 10px">
      <template #header>
        <div style="font-weight: bold; font-size: 18px">Wafer 测试信息</div>
      </template>

      <el-descriptions
        :column="4"
        border
        size="small"
        label-style="font-weight: bold; width: 100px;"
      >
        <el-descriptions-item label="操作员">{{
          header.operatorName
        }}</el-descriptions-item>
        <el-descriptions-item label="设备">{{
          header.deviceName
        }}</el-descriptions-item>
        <el-descriptions-item label="晶圆尺寸">{{
          header.waferSize
        }}</el-descriptions-item>
        <el-descriptions-item label="机台号">{{
          header.machineNo
        }}</el-descriptions-item>

        <el-descriptions-item label="Lot No">{{
          header.lotNo
        }}</el-descriptions-item>
        <el-descriptions-item label="Slot No">{{
          header.slotNo
        }}</el-descriptions-item>
        <el-descriptions-item label="Wafer ID">{{
          header.waferId
        }}</el-descriptions-item>
        <el-descriptions-item label="探针次数">{{
          header.numOfProbing
        }}</el-descriptions-item>

        <el-descriptions-item label="测试时间">
          {{ header.waferTestingStartTime }} ~ {{ header.waferTestingEndTime }}
        </el-descriptions-item>
        <el-descriptions-item label="总 Die">{{
          header.totalTestedDice
        }}</el-descriptions-item>
        <el-descriptions-item label="良品">{{
          header.totalPassDice
        }}</el-descriptions-item>
        <el-descriptions-item label="不良品">{{
          header.totalFailDice
        }}</el-descriptions-item>
        <el-descriptions-item label="初始x坐标">{{
          header.firstDieCoordinatorX
        }}</el-descriptions-item>
        <el-descriptions-item label="初始y坐标">{{
          header.firstDieCoordinatorY
        }}</el-descriptions-item>
        <el-descriptions-item label="linesize">{{
          header.mapDataAreaLineSize
        }}</el-descriptions-item>
        <el-descriptions-item label="rowsize">{{
          header.mapDataAreaRowSize
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <div class="config">
      <el-button @click="showBinValue = !showBinValue">
        {{ showBinValue ? "隐藏 Bin 值" : "显示 Bin 值" }}
      </el-button>
      <div class="upload-section">
        <el-upload
          class="upload-demo"
          :action="API_URL_DatParser"
          :on-success="handleSuccess"
          :before-upload="beforeUpload"
          :file-list="fileList"
          :show-file-list="false"
          :limit="1"
          :http-request="customRequest"
        >
          <el-button type="primary">上传DAT文件</el-button>
        </el-upload>
      </div>
    </div>

    <div style="position: relative; display: flex">
      <div class="left-content">
        <canvas
          ref="canvasRef"
          :width="canvasWidth"
          :height="canvasHeight"
          style="border: 1px solid #ccc; background-color: #f0f0f0"
          @mousedown="handleMouseDown"
          @mousemove="handleMouseMove"
          @mouseup="handleMouseUp"
          @mouseleave="handleMouseUp"
          @wheel.prevent="handleWheel"
          @contextmenu.prevent="handleRightClick"
        ></canvas>
      </div>

      <div
        v-if="hoverData"
        :style="{
          position: 'absolute',
          top: `${hoverData.screenY}px`,
          left: `${hoverData.screenX}px`,
          background: '#333',
          color: '#fff',
          padding: '4px 6px',
          borderRadius: '4px',
          fontSize: '12px',
          pointerEvents: 'none'
        }"
      >
        X: {{ hoverData.x }}, Y: {{ hoverData.y }}<br />
        {{ hoverData.value }}
        <br />
      </div>

      <!-- 修改记录区 -->
      <div class="right-content">
        <el-card class="record-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <el-icon><UploadFilled /></el-icon>
              <span>批量更新 DAT 数据</span>
            </div>
          </template>

          <div class="button-group">
            <el-button type="primary" plain @click="triggerCsvInput">
              <el-icon><FolderOpened /></el-icon>
              上传 CSV 文件夹
            </el-button>
            <input
              ref="csvInput"
              type="file"
              webkitdirectory
              multiple
              style="display: none"
              @change="handleCsvChange"
            />
            <div v-if="csvFiles.length" class="file-info">
              已选择 {{ csvFiles.length }} 个 CSV 文件
            </div>

            <el-button type="success" plain @click="triggerDatInput">
              <el-icon><FolderOpened /></el-icon>
              上传 DAT 文件夹
            </el-button>
            <input
              ref="datInput"
              type="file"
              webkitdirectory
              multiple
              style="display: none"
              @change="handleDatChange"
            />
            <div v-if="datFiles.length" class="file-info">
              已选择 {{ datFiles.length }} 个 DAT 文件
            </div>
          </div>

          <el-divider></el-divider>

          <el-button type="danger" @click="submit" style="width: 100%">
            <el-icon><DocumentChecked /></el-icon>
            提交并更新
          </el-button>
        </el-card>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { ElMessage, ElLoading } from "element-plus";
import axios from "axios";
import {
  UploadFilled,
  FolderOpened,
  DocumentChecked
} from "@element-plus/icons-vue";

defineOptions({
  name: "DatShow"
});

const canvasRef = ref(null);
const canvasWidth = 900;
const canvasHeight = 1000;
const gridSize = 8;

const dies = ref([]);
const header = ref(null);
const hoverData = ref(null);

const minX = ref(0);
const maxX = ref(0);
const minY = ref(0);
const maxY = ref(0);
const offsetX = ref(0);
const offsetY = ref(0);

const scale = ref(1); // 缩放倍数
const panX = ref(0); // 平移（暂未使用，可后续加拖动）
const panY = ref(0);
const isDragging = ref(false);
const dragStart = ref({ x: 0, y: 0 });
const lastPan = ref({ x: 0, y: 0 });
const showBinValue = ref(false); // 👈 控制是否显示Bin值

// const API_URL_DatParser = "https://localhost:44389/api/datParser/parser";
// const API_URL_updateDat = "https://localhost:44389/api/updateDat";
const API_URL_updateDat = "http://10.20.5.21:8080/api/updateDat";
const API_URL_DatParser = "http://10.20.5.21:8080/api/datParser/parser";

// const modificationRecords = ref([]); // 用来记录所有修改的坐标和新的 Bin 值

// dat文件
const fileList = ref([]);

const csvFiles = ref([]);
const datFiles = ref([]);

const csvInput = ref(null);
const datInput = ref(null);

const triggerCsvInput = () => csvInput.value.click();
const triggerDatInput = () => datInput.value.click();

let loadingInstance = null;

function getDieColor(die) {
  // if (die.dummyData === "1") return "#00008B"; // 深蓝色 Dummy
  // if (die.marking === "M") return "#FFD700"; // 黄色 M
  // // if (die.samplingDie === "S") return "#800080"; // 紫色 S
  // if (die.extendedBinaryCategry == 0) return "#008000"; // 绿色 P
  // if (die.dieTestResult !== "0") return "#FF0000"; // 红色 Fail
  // if (die.dieProperty == 0) return "#FFD700";
  // return "#FFD700"; // 默认灰色
  if (die.dummyData === "1") return "#00008B";
  if (die.dieProperty == 0) return "#800080";
  if (die.dieProperty == 2) return "#FFD700";
  if (die.dieTestResult == 1) return "#008000";
  if (die.dieTestResult == 2) return "#FF0000";
  return "grey";
}

// 状态文字
function getDieLabel(die) {
  if (die.dieTestResult == 1) return "P";
  if (die.dieTestResult == 2) return "F";
  if (die.dieProperty == 0 && die.dummyData != 1) return "S";
  if (die.dieProperty == 2) return "M";

  return "";
}

function draw() {
  const canvas = canvasRef.value;
  if (!canvas || dies.value.length === 0) return;

  const ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);

  for (const die of dies.value) {
    const x = die.dieCoordinatorValuesX;
    const y = die.dieCoordinatorValueY;

    const drawX =
      offsetX.value + (x - minX.value) * gridSize * scale.value + panX.value;
    const drawY =
      offsetY.value + (y - minY.value) * gridSize * scale.value + panY.value;
    const size = gridSize * scale.value;

    ctx.fillStyle = getDieColor(die);
    ctx.fillRect(drawX, drawY, size - 1, size - 1);

    if (scale.value >= 2) {
      ctx.fillStyle = "#fff";
      ctx.font = `${Math.floor(size / 2)}px Arial`;
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";

      if (showBinValue.value) {
        // 👉 只显示 Bin 值
        ctx.fillStyle = "#000";
        ctx.fillText(
          die.categoryData?.toString() ?? "",
          drawX + size / 2,
          drawY + size / 2
        );
      } else {
        // 👉 显示状态标记 P/F/S/M
        const label = getDieLabel(die);
        if (label) {
          ctx.fillStyle = "#fff";
          ctx.font = `${Math.floor(size / 2)}px Arial`;
          ctx.textAlign = "center";
          ctx.textBaseline = "middle";
          ctx.fillText(label, drawX + size / 2, drawY + size / 2);
        }
      }
    }
  }
}

// 右键修改
// const handleRightClick = event => {
//   const rect = canvasRef.value.getBoundingClientRect();
//   const x = Math.floor(
//     (event.clientX - rect.left - offsetX.value - panX.value) /
//       (gridSize * scale.value) +
//       minX.value
//   );
//   const y = Math.floor(
//     (event.clientY - rect.top - offsetY.value - panY.value) /
//       (gridSize * scale.value) +
//       minY.value
//   );
//   const die = dies.value.find(
//     d =>
//       d.dieCoordinatorValuesX === x &&
//       d.dieCoordinatorValueY === y &&
//       d.dummyData != 1
//   );

//   if (die) {
//     const newBin = prompt("请输入新的 Bin 值：", die.categoryData);
//     const porF = prompt(
//       "请输入是否是PASS，PASS填1，Fail填2：",
//       die.dieTestResult
//     );
//     if (newBin) {
//       if (newBin != die.categoryData) {
//         // 记录修改的坐标和新值
//         modificationRecords.value.push({
//           x: die.dieCoordinatorValuesX,
//           y: die.dieCoordinatorValueY,
//           coordinates: `(${die.dieCoordinatorValuesX}, ${die.dieCoordinatorValueY})`,
//           newBin: newBin,
//           isPass: die.dieTestResult == 1 ? "P" : "F"
//         });
//       }

//       die.categoryData = newBin; // 更新 Bin 值
//       die.dieTestResult = porF;
//       die.extendedBinaryCategry = newBin;
//       draw(); // 重新绘制
//     }
//   }
// };

function handleMouseDown(event) {
  isDragging.value = true;
  dragStart.value = { x: event.clientX, y: event.clientY };
  lastPan.value = { x: panX.value, y: panY.value };
}

function handleMouseMove(event) {
  if (isDragging.value) {
    const dx = event.clientX - dragStart.value.x;
    const dy = event.clientY - dragStart.value.y;
    panX.value = lastPan.value.x + dx;
    panY.value = lastPan.value.y + dy;
    draw();
  } else {
    // 非拖动状态下的悬浮逻辑
    const rect = canvasRef.value.getBoundingClientRect();
    const x = Math.floor(
      (event.clientX - rect.left - offsetX.value - panX.value) /
        (gridSize * scale.value) +
        minX.value
    );
    const y = Math.floor(
      (event.clientY - rect.top - offsetY.value - panY.value) /
        (gridSize * scale.value) +
        minY.value
    );
    const die = dies.value.find(
      d =>
        d.dieCoordinatorValuesX === x &&
        d.dieCoordinatorValueY === y &&
        d.dummyData != 1
    );
    if (die) {
      hoverData.value = {
        x,
        y,
        value: `Bin: ${die.categoryData} Site : ${die.extendedTestExecutionSite + 1}`,
        screenX: event.clientX - rect.left + 10,
        screenY: event.clientY - rect.top + 10
      };
    } else {
      hoverData.value = null;
    }
  }
}

function handleMouseUp() {
  isDragging.value = false;
}

// 缩放事件
function handleWheel(event) {
  const zoomFactor = 0.1;
  if (event.deltaY < 0) {
    scale.value = Math.min(scale.value + zoomFactor, 5);
  } else {
    scale.value = Math.max(scale.value - zoomFactor, 0.2);
  }
  draw();
}

const beforeUpload = file => {
  const isDat = file.type === ""; // 可以根据实际类型调整
  if (!isDat) {
    ElMessage.error("文件类型错误");
  }
  return isDat;
};

const handleSuccess = (response, file) => {
  if (!response) {
    console.log("Invalid response:", response);
    return;
  }

  console.log("文件解析成功", response);
  header.value = response.header;
  dies.value = response.dies;

  // 获取坐标范围
  minX.value = Math.min(...dies.value.map(d => d.dieCoordinatorValuesX));
  maxX.value = Math.max(...dies.value.map(d => d.dieCoordinatorValuesX));
  minY.value = Math.min(...dies.value.map(d => d.dieCoordinatorValueY));
  maxY.value = Math.max(...dies.value.map(d => d.dieCoordinatorValueY));

  offsetX.value = (canvasWidth - (maxX.value - minX.value + 1) * gridSize) / 2;
  offsetY.value = (canvasHeight - (maxY.value - minY.value + 1) * gridSize) / 2;

  draw();

  fileList.value = [];
};

const customRequest = async ({ file, onSuccess, onError }) => {
  const formData = new FormData();
  formData.append("file", file);

  loadingInstance = ElLoading.service({
    lock: true,
    text: "正在解析dat文件，请稍候...",
    background: "rgba(0,0,0,0.3)"
  });

  try {
    const response = await fetch(API_URL_DatParser, {
      method: "POST",
      body: formData
    });

    if (response.ok) {
      const result = await response.json();
      onSuccess(result, file);
    } else {
      onError(new Error("上传失败"));
    }
  } catch (error) {
    onError(error);
  } finally {
    if (loadingInstance) {
      loadingInstance.close();
    }
  }
};

const handleCsvChange = e => {
  const allFiles = Array.from(e.target.files);

  // 过滤出不是 csv 的文件
  const invalidFiles = allFiles.filter(file => {
    return !file.name.toLowerCase().endsWith(".csv");
  });

  if (invalidFiles.length > 0) {
    ElMessage.warning(
      `请只上传 .csv 文件，以下文件格式不正确：\n${invalidFiles.map(f => f.name).join("\n")}`
    );
    csvFiles.value = []; // 清空上传记录，防止误操作
    return;
  }

  // 所有文件合法
  csvFiles.value = allFiles;
};

const handleDatChange = e => {
  datFiles.value = Array.from(e.target.files);
};

const getBasename = filename => {
  if (filename.endsWith(".csv")) {
    return filename.substring(0, filename.lastIndexOf(".")).toLowerCase();
  }
  if (filename.endsWith(".dat")) {
    return filename.substring(0, filename.lastIndexOf(".")).toLowerCase();
  }
  return filename;
};

const checkFileNameMatch = () => {
  const csvNames = csvFiles.value.map(f => getBasename(f.name).toLowerCase());
  const datNames = datFiles.value.map(f => getBasename(f.name).toLowerCase());

  const csvSet = new Set(csvNames);
  const datSet = new Set(datNames);

  // 先检查数量是否一致
  if (csvSet.size !== datSet.size) return false;

  // 每个 csv 文件是否在 dat 中找到对应项
  return [...csvSet].every(name => datSet.has(name));
};

const submit = async () => {
  if (!checkFileNameMatch()) {
    ElMessage.warning("CSV 与 DAT 文件名不一致，请检查！");
    return;
  }

  const formData = new FormData();
  csvFiles.value.forEach(file => {
    formData.append("csvFiles", file, file.name);
  });
  datFiles.value.forEach(file => {
    formData.append("datFiles", file, file.name);
  });

  try {
    const response = await axios.post(API_URL_updateDat, formData, {
      responseType: "blob"
    });

    const blob = new Blob([response.data], { type: "application/zip" });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "update.zip";
    a.click();
    window.URL.revokeObjectURL(url);
  } catch (error) {
    let msg = "下载失败";
    if (error.response && error.response.status === 500) {
      // 尝试从后端返回的字符串中获取具体错误信息
      msg = `服务器错误：${error.response}`;
    }

    ElMessage.error(msg);
  }
};

onMounted(async () => {
  const response = await fetch(API_URL_DatParser);
  const data = await response.json();

  header.value = data.header;
  dies.value = data.dies;

  // 获取坐标范围
  minX.value = Math.min(...dies.value.map(d => d.dieCoordinatorValuesX));
  maxX.value = Math.max(...dies.value.map(d => d.dieCoordinatorValuesX));
  minY.value = Math.min(...dies.value.map(d => d.dieCoordinatorValueY));
  maxY.value = Math.max(...dies.value.map(d => d.dieCoordinatorValueY));

  offsetX.value = (canvasWidth - (maxX.value - minX.value + 1) * gridSize) / 2;
  offsetY.value = (canvasHeight - (maxY.value - minY.value + 1) * gridSize) / 2;

  draw();
});
</script>

<style scoped lang="scss">
.config {
  display: flex;
  align-items: center;
}

.upload-section {
  display: flex;
  align-items: center;
  margin-left: 10px;
}

.parse-btn {
  margin-left: 10px;
  display: flex;
  align-items: center;
}

.el-table {
  width: 100%;
}

.right-content {
  display: flex;
  justify-content: center;
  padding: 20px;
}

.record-card {
  width: 360px;
  border-radius: 10px;
  padding: 20px;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 18px;
  font-weight: 600;
}

.button-group {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 10px;
}

.file-info {
  font-size: 12px;
  color: #888;
  margin-left: 4px;
}
</style>
